<?php
namespace Library;

use Illuminate\Support\Facades\Http;
use Alipay\OpenAPISDK\Api\AlipayTradeApi;
use Alipay\OpenAPISDK\Util\Model\AlipayConfig;
use Alipay\OpenAPISDK\Util\AlipayConfigUtil;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log; 
use \Alipay\OpenAPISDK\ApiException;
use Alipay\OpenAPISDK\Util\GenericExecuteApi;
use Alipay\OpenAPISDK\Util\Model\CustomizedParams;
use Alipay\OpenAPISDK\Util\Model\OpenApiGenericRequest;




class AlipayF2F {
    private $appId;
    private $privateKey;
    private $alipayPublicKey;
    private $signType = 'RSA2';
    public $payModel;
    public $bizContent;
    public $method;
    public $notifyUrl;
    public $response;
    
    

    public function __construct()
    {
    }

    private function formatPrivateKey($privateKey) {
        if (strpos($privateKey, '-----BEGIN RSA PRIVATE KEY-----') === false) {
            // return "-----BEGIN RSA PRIVATE KEY-----\n" .
            //     wordwrap($privateKey, 64, "\n", true) .
            //     "-----END RSA PRIVATE KEY-----\n";
            $privateKey        = chunk_split($privateKey, 64, "\n");
            $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n$privateKey-----END RSA PRIVATE KEY-----\n";
            return $privateKey;
        }
        return $privateKey;
    }

    private function formatPublicKey($publicKey) {
        if (strpos($publicKey, '-----BEGIN PUBLIC KEY-----') === false) {
            // return "-----BEGIN PUBLIC KEY-----\n" .
            //     wordwrap($publicKey, 64, "\n", true) .
            //     "-----END PUBLIC KEY-----\n";
            $publicKey = chunk_split($publicKey, 64, "\n");
            $publicKey = "-----BEGIN PUBLIC KEY-----\n$publicKey-----END PUBLIC KEY-----\n";
            return $publicKey;
        }
        return $publicKey;
    }


    public function pay()
    {
        // 初始化SDK
        $alipayConfigUtil = new AlipayConfigUtil($this->getAlipayConfig());

        $apiInstance = new GenericExecuteApi(
            $alipayConfigUtil,
            new Client()
        );
        // 构造请求参数以调用接口
        $bizParams = array();
        $bizContent = array();

        // 设置商户订单号
        $bizContent['out_trade_no'] = "20150320010101001";

        // 设置订单总金额
        $bizContent['total_amount'] = "88.88";

        // 设置订单标题
        $bizContent['subject'] = "Iphone6 16G";

        // 设置产品码
        $bizContent['product_code'] = "FAST_INSTANT_TRADE_PAY";

        // 设置订单附加信息
        $bizContent['body'] = "Iphone6 16G";

        // 设置PC扫码支付的方式
        $bizContent['qr_pay_mode'] = "1";

        // 设置商户自定义二维码宽度
        $bizContent['qrcode_width'] = 100;

        // 设置订单包含的商品列表信息
        $goodsDetail = array();
        $goodsDetail0 = array();
        $goodsDetail0['out_sku_id'] = "outSku_01";
        $goodsDetail0['goods_name'] = "ipad";
        $goodsDetail0['alipay_goods_id'] = "20010001";
        $goodsDetail0['quantity'] = 1;
        $goodsDetail0['price'] = "2000";
        $goodsDetail0['out_item_id'] = "outItem_01";
        $goodsDetail0['goods_id'] = "apple-01";
        $goodsDetail0['goods_category'] = "34543238";
        $goodsDetail0['categories_tree'] = "124868003|126232002|126252004";
        $goodsDetail0['show_url'] = "http://www.alipay.com/xxx.jpg";
        $goodsDetail[] = $goodsDetail0;
        $bizContent['goods_detail'] = $goodsDetail;

        // 设置订单绝对超时时间
        $bizContent['time_expire'] = "2016-12-31 10:05:01";

        // 设置建议使用time_expire字段
        $bizContent['timeout_express'] = "90m";

        // 设置描述分账信息
        $royaltyInfo = array();
        $royaltyInfo['royalty_type'] = "ROYALTY";
        $royaltyDetailInfos = array();
        $royaltyDetailInfos0 = array();
        $royaltyDetailInfos0['out_relation_id'] = "20131124001";
        $royaltyDetailInfos0['amount_percentage'] = "100";
        $royaltyDetailInfos0['amount'] = "0.1";
        $royaltyDetailInfos0['batch_no'] = "123";
        $royaltyDetailInfos0['trans_in'] = "2088101126708402";
        $royaltyDetailInfos0['trans_out_type'] = "userId";
        $royaltyDetailInfos0['trans_out'] = "2088101126765726";
        $royaltyDetailInfos0['serial_no'] = 1;
        $royaltyDetailInfos0['trans_in_type'] = "userId";
        $royaltyDetailInfos0['desc'] = "分账测试1";
        $royaltyDetailInfos[] = $royaltyDetailInfos0;
        $royaltyInfo['royalty_detail_infos'] = $royaltyDetailInfos;
        $bizContent['royalty_info'] = $royaltyInfo;

        // 设置二级商户信息
        $subMerchantMjTAb = array();
        $subMerchantMjTAb['merchant_id'] = "2088000603999128";
        $subMerchantMjTAb['merchant_type'] = "alipay";
        $bizContent['sub_merchant'] = $subMerchantMjTAb;

        // 设置描述结算信息
        $settleInfo = array();
        $settleInfo['settle_period_time'] = "7d";
        $settleDetailInfos = array();
        $settleDetailInfos0 = array();
        $settleDetailInfos0['amount'] = "0.1";
        $settleDetailInfos0['trans_in'] = "A0001";
        $settleDetailInfos0['settle_entity_type'] = "SecondMerchant";
        $settleDetailInfos0['summary_dimension'] = "A0001";
        $settleDetailInfos0['actual_amount'] = "0.1";
        $settleDetailInfos0['settle_entity_id'] = "2088xxxxx;ST_0001";
        $settleDetailInfos0['trans_in_type'] = "cardAliasNo";
        $settleDetailInfos[] = $settleDetailInfos0;
        $settleInfo['settle_detail_infos'] = $settleDetailInfos;
        $bizContent['settle_info'] = $settleInfo;

        // 设置业务扩展参数
        $extendParams = array();
        $extendParams['sys_service_provider_id'] = "2088511833207846";
        $extendParams['hb_fq_seller_percent'] = "100";
        $extendParams['hb_fq_num'] = "3";
        $extendParams['tc_installment_order_id'] = "2015042321001004720200028594";
        $extendParams['industry_reflux_info'] = "{\"scene_code\":\"metro_tradeorder\",\"channel\":\"xxxx\",\"scene_data\":{\"asset_name\":\"ALIPAY\"}}";
        $extendParams['specified_seller_name'] = "XXX的跨境小铺";
        $extendParams['royalty_freeze'] = "true";
        $extendParams['card_type'] = "S0JP0000";
        $extendParams['credit_ext_info'] = "{\"category\":\"CHARGE_PILE_CAR\",\"serviceId\":\"2020042800000000000001450466\"}";
        $extendParams['trade_component_order_id'] = "2023060801502300000008810000005657";
        $bizContent['extend_params'] = $extendParams;

        // 设置商户传入业务信息
        $bizContent['business_params'] = "{\"mc_create_trade_ip\":\"127.0.0.1\"}";

        // 设置优惠参数
        $bizContent['promo_params'] = "{\"storeIdType\":\"1\"}";

        // 设置请求后页面的集成方式
        $bizContent['integration_type'] = "PCWEB";

        // 设置请求来源地址
        $bizContent['request_from_url'] = "https://";

        // 设置签约参数
        $agreementSignParams = array();
        $subMerchanthCwEH = array();
        $subMerchanthCwEH['sub_merchant_name'] = "滴滴出行";
        $subMerchanthCwEH['sub_merchant_service_name'] = "滴滴出行免密支付";
        $subMerchanthCwEH['sub_merchant_service_description'] = "免密付车费，单次最高500";
        $subMerchanthCwEH['sub_merchant_id'] = "2088123412341234";
        $agreementSignParams['sub_merchant'] = $subMerchanthCwEH;
        $agreementSignParams['buckle_app_id'] = "1001164";
        $agreementSignParams['sign_validity_period'] = "2m";
        $agreementSignParams['buckle_merchant_id'] = "268820000000414397785";
        $agreementSignParams['external_logon_id'] = "138****8888";
        $agreementSignParams['third_party_type'] = "PARTNER";
        $agreementSignParams['personal_product_code'] = "GENERAL_WITHHOLDING_P";
        $agreementSignParams['external_agreement_no'] = "test";
        $agreementSignParams['promo_params'] = "{\"key\",\"value\"}";
        $agreementSignParams['sign_scene'] = "INDUSTRY|CARRENTAL";
        $bizContent['agreement_sign_params'] = $agreementSignParams;

        // 设置商户门店编号
        $bizContent['store_id'] = "NJ_001";

        // 设置指定支付渠道
        $bizContent['enable_pay_channels'] = "pcredit,moneyFund,debitCardExpress";

        // 设置禁用渠道
        $bizContent['disable_pay_channels'] = "pcredit,moneyFund,debitCardExpress";

        // 设置商户的原始订单号
        $bizContent['merchant_order_no'] = "20161008001";

        // 设置外部指定买家
        $extUserInfo = array();
        $extUserInfo['cert_type'] = "IDENTITY_CARD";
        $extUserInfo['cert_no'] = "362334768769238881";
        $extUserInfo['name'] = "李明";
        $extUserInfo['mobile'] = "16587658765";
        $extUserInfo['min_age'] = "18";
        $extUserInfo['need_check_info'] = "F";
        $extUserInfo['identity_hash'] = "27bfcd1dee4f22c8fe8a2374af9b660419d1361b1c207e9b41a754a113f38fcc";
        $bizContent['ext_user_info'] = $extUserInfo;

        // 设置开票信息
        $invoiceInfo = array();
        $keyInfo = array();
        $keyInfo['tax_num'] = "1464888883494";
        $keyInfo['is_support_invoice'] = true;
        $keyInfo['invoice_merchant_name'] = "ABC|003";
        $invoiceInfo['key_info'] = $keyInfo;
        $invoiceInfo['details'] = "[{\"code\":\"100294400\",\"name\":\"服饰\",\"num\":\"2\",\"sumPrice\":\"200.00\",\"taxRate\":\"6%\"}]";
        $bizContent['invoice_info'] = $invoiceInfo;

        // 设置返回参数选项
        $queryOptions = array();
        $queryOptions[] = "hyb_amount";
        $queryOptions[] = "enterprise_pay_info";
        $bizContent['query_options'] = $queryOptions;

        $bizParams['biz_content'] = $bizContent;

        try {
            // 如果是第三方代调用模式，请设置app_auth_token（应用授权令牌）
            $pageRedirectionData = $apiInstance->pageExecute('alipay.trade.page.pay', 'POST', $bizParams, null,null);
            Log::info('pageRedirectionData', [$pageRedirectionData]);
            // 如果需要返回GET请求，请使用
            // $pageRedirectionData = $apiInstance->pageExecute('alipay.trade.page.pay', 'GET', $bizParams);
            // print_r($pageRedirectionData);
            $this->response = $pageRedirectionData; 
        } catch (ApiException $e) {
            echo '调用失败: ', $e->getMessage(), PHP_EOL;
            echo 'body: ', $e->getResponseBody(), PHP_EOL;
            echo 'header: ', $e->getResponseHeaders(), PHP_EOL;
        }


        // $apiInstance =  new AlipayTradeApi(
        //     new Client()
        // );
        // $alipayConfig = new AlipayConfig();
        // $alipayConfig->setAppId('2021005104607475');
        // // 密钥模式
        // Log::info('alipayConfig', [$this->privateKey, $this->alipayPublicKey]);
        // $alipayConfig->setEncryptKey('B9BUDNajG93558oGC3ym0g==');
        // $alipayConfig->setPrivateKey($this->privateKey);
        // $alipayConfig->setAlipayPublicKey($this->alipayPublicKey);
       
        

        // $alipayConfigUtil = new AlipayConfigUtil($alipayConfig);
        // $apiInstance->setAlipayConfigUtil($alipayConfigUtil);
        // try {
        //     $this->response = $apiInstance->pay($this->payModel);
        // } catch (ApiException $e) {
        //     echo 'Exception when calling AlipayTradeApi->pay: ', $e->getMessage(), PHP_EOL;
        //     echo 'body: ', $e->getResponseBody(), PHP_EOL;
        //     echo 'header: ', $e->getResponseHeaders(), PHP_EOL;
        // }


    }

    public function getAlipayConfig()
    {
        $alipayConfig = new AlipayConfig();
        $alipayConfig->setServerUrl('https://openapi.alipay.com');
        $alipayConfig->setAppId('2021005104607475');
        $alipayConfig->setPrivateKey($this->privateKey);
        $alipayConfig->setAlipayPublicKey($this->alipayPublicKey);
        return $alipayConfig;
    }

    public function verify($data): bool
    {
        if (is_string($data)) {
            parse_str($data, $data);
        }
        $sign = $data['sign'];
        unset($data['sign']);
        unset($data['sign_type']);
        ksort($data);
        $data = $this->buildQuery($data);
        $res = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($this->alipayPublicKey, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";
        if ("RSA2" == $this->signType) {
            $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
        } else {
            $result = (openssl_verify($data, base64_decode($sign), $res) === 1);
        }
        openssl_free_key(openssl_get_publickey($res));
        return $result;
    }

    public function setBizContent($bizContent = [])
    {
        $this->bizContent = json_encode($bizContent);
    }

    public function setMethod($method)
    {
        $this->method = $method;
    }

    public function setAppId($appId)
    {
        $this->appId = $appId;
    }

    public function setPrivateKey($privateKey)
    {
        $this->privateKey = $privateKey;
    }

    public function setAlipayPublicKey($alipayPublicKey)
    {
        $this->alipayPublicKey = $alipayPublicKey;
    }

    public function setNotifyUrl($url)
    {
        $this->notifyUrl = $url;
    }

    public function send()
    {
        $response = Http::get('https://openapi.alipay.com/gateway.do', $this->buildParam())->json();
        $resKey = str_replace('.', '_', $this->method) . '_response';
        if (!isset($response[$resKey])) throw new \Exception('从支付宝请求失败');
        $response = $response[$resKey];
        if ($response['msg'] !== 'Success') throw new \Exception($response['sub_msg']);
        $this->response = $response;
    }

    public function getQrCodeUrl()
    {
        $response = $this->response;
        if (!isset($response['qr_code'])) throw new \Exception('获取付款二维码失败');
        return $response['qr_code'];
    }

    public function getResponse()
    {
        return $this->response;
    }

    public function buildParam(): array
    {
        $params = [
            'app_id' => $this->appId,
            'method' => $this->method,
            'charset' => 'UTF-8',
            'sign_type' => $this->signType,
            'timestamp' => date('Y-m-d H:m:s'),
            'biz_content' => $this->bizContent,
            'version' => '1.0',
            '_input_charset' => 'UTF-8'
        ];
        if ($this->notifyUrl) $params['notify_url'] = $this->notifyUrl;
        ksort($params);
        $params['sign'] = $this->buildSign($this->buildQuery($params));
        return $params;
    }

    public function buildQuery($query)
    {
        if (!$query) {
            throw new \Exception('参数构造错误');
        }
        //将要 参数 排序
        ksort($query);

        //重新组装参数
        $params = array();
        foreach ($query as $key => $value) {
            $params[] = $key . '=' . $value;
        }
        $data = implode('&', $params);
        return $data;
    }

    private function buildSign(string $signData): string
    {
        $privateKey = $this->privateKey;
        $p_key = array();
        //如果私钥是 1行
        if (!stripos($privateKey, "\n")) {
            $i = 0;
            while ($key_str = substr($privateKey, $i * 64, 64)) {
                $p_key[] = $key_str;
                $i++;
            }
        }
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
        $privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";

        //私钥
        $privateId = openssl_pkey_get_private($privateKey, '');

        // 签名
        $signature = '';

        if ("RSA2" == $this->signType) {

            openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA256);
        } else {

            openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA1);
        }

        openssl_free_key($privateId);

        //加密后的内容通常含有特殊字符，需要编码转换下
        $signature = base64_encode($signature);
        return $signature;
    }
}
